home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Sample Code / Snippets / Toolbox / OtherResInfo-MungeDeamon / OtherResInfo.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-22  |  60.4 KB  |  1,587 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2. #
  3. #   Apple Developer Technical Support
  4. #
  5. #   OtherResInfo
  6. #    Answering the perenial question....
  7. #    How can I mess around in someone else's resource fork 
  8. #    without getting their resources    in my chain?
  9. #
  10. #   OtherResInfo.c  -   C Source
  11. #
  12. #   Copyright © 1992 Apple Computer, Inc.
  13. #   All rights reserved.
  14. #
  15. #   Versions:   
  16. #               1.0               12/92       C.K. Haun <TR>
  17. #    Here's one nice System 7 way.
  18. #    I use a seperate, background-only application to do the actual manipulation 
  19. #    of the resource fork of the other application.  
  20. #    The backgrounder tells the foreground app what it's found with AppleEvents.
  21. #    The backgrounder has (runtime-wise) only one resource to care about, it's 
  22. #    Main code segement, so it is never worried about pulling in any stray 
  23. #    resources from the other resource fork.
  24. #    Also, since you can have the backgrounder quit right after it does it's work, you
  25. #    do not need to worry about "Should I close the other resource fork, 
  26. #    was it already open, has it been opened since I started working" and so on.  
  27. #    By having the backgrounder quit, you're letting the Process Manager 
  28. #    worry about keeping the resource fork open, not you.
  29. #    
  30. #    And anyway, it's a nice demo of how you can use a background-only app to do dirty work for you.
  31. #     Written by C.K. Haun <TR> 
  32. #     Apple Developer Tech Support 
  33. #     Of course, Copyright 1992, Apple Computer Inc. 
  34. #   ---------------------------------------------------------------
  35. #   Use this sample as a starting point, and adapt its' routines to 
  36. #   meet the specific needs of your project.  
  37. #   This sample will grow as more edition types are implemented,
  38. #   periodically check AppleLink for a later, expanded sample.
  39. #   This application is an example of the form of a Macintosh 
  40. #   application; it is NOT a template. It is NOT intended to be 
  41. #   used as a foundation for the next world-class, best-selling, 
  42. #   600K application. A stick figure drawing of the human body may 
  43. #   be a good example of the form for a painting, but that does not 
  44. #   mean it should be used as the basis for the next Mona Lisa.
  45. #
  46. #
  47. ------------------------------------------------------------------------------*/
  48.  
  49. #include "OtherResInfo.h"
  50.  
  51. /* globals */
  52. Boolean gQuit, gInBackground;
  53. unsigned long gMySleep=kFrontSleep;  /* I don't need to take up a lot of time when I'm frontmost */
  54. ProcessSerialNumber gOurSN;
  55.  
  56. short gHelpItem;
  57. extraDialogFilter gExtraDialogFilter;
  58.  
  59.  
  60.  
  61. #pragma segment Main
  62.  
  63.  
  64.  
  65. main()
  66. {
  67.     EventRecord myEventRecord;
  68.     WindowPtr twindow;
  69.     short fHit;
  70.     windowCHandle tempWCH;
  71.     
  72.     UnloadSeg((Ptr)_DataInit);                              /* throw out setup code */
  73.     InitalizeApp();
  74.     UnloadSeg((Ptr)InitalizeApp);                           /* get rid of my initialization code */
  75.     do {
  76.  
  77.         WaitNextEvent(everyEvent, &myEventRecord, gMySleep, nil);
  78.  
  79.         switch (myEventRecord.what) {
  80.  
  81.             case nullEvent:
  82.                 /* no nul processing in this sample */
  83.                 break;
  84.  
  85.             case updateEvt:
  86.                 /* always check to see if it's my window */
  87.                 /* this may not seem necessary under 7.0, where it's unlikely or impossible for */
  88.                 /* a DA to be in your layer, but there are others */
  89.                 /* who can stick themselves into your window list, */
  90.                 /* BalloonWriter comes quickly to mind */
  91.                 if (IsMyWindow((WindowPtr)myEventRecord.message)) {
  92.                     tempWCH = (windowCHandle)GetWRefCon((WindowPtr)myEventRecord.message);
  93.                     ((*tempWCH)->drawMe)((WindowPtr)myEventRecord.message);
  94.                 }
  95.                 break;
  96.  
  97.             case mouseDown:
  98.                 /* first see where the hit was */
  99.                 fHit = FindWindow(myEventRecord.where, &twindow);
  100.                 switch (fHit) {
  101.                     Rect limitRect;
  102.                     Str255 tempString;
  103.                     long back;
  104.  
  105.                     case inDesk:                            /* if they hit in desk, then the process manager */
  106.                         break;                              /* will switch us out, we don't need to do anything */
  107.  
  108.                     case inMenuBar:
  109.                         AdjustMenus();
  110.                         DoSelected(MenuSelect(myEventRecord.where));
  111.                         break;
  112.                         
  113.                     case inSysWindow:
  114.                         /* pass to the system */
  115.                         SystemClick(&myEventRecord, twindow);
  116.                         break;
  117.  
  118.                     case inContent:
  119.                         /* Handle content and control clicks here */
  120.                         if (FrontWindow()==twindow) {                /* don't do this unless we have a window open, silly */
  121.                             windowCHandle clicker;
  122.                             clicker = (windowCHandle)GetWRefCon(twindow);
  123.                             /* jump to the content function stored for this window */
  124.                             HLock((Handle)clicker);         /* lock it down so things don't get stupid */
  125.                             ((*clicker)->clickMe)(twindow);
  126.                             HUnlock((Handle)clicker);       /* all done */
  127.                         } else {
  128.                         /* bring this window forward */
  129.                             SelectWindow(twindow);                     /* select the window */
  130.                             SetPort(twindow);
  131.  
  132.                         }
  133.                         break;
  134.  
  135.                     case inDrag:
  136.                         DragWindow(twindow, myEventRecord.where, &qd.screenBits.bounds);
  137.                         break;
  138.  
  139.                     case inGrow:
  140.                         /* Call GrowWindow here if you have a grow box */
  141.  
  142.                         SetPort(twindow);
  143.                         limitRect = qd.screenBits.bounds;
  144.                         limitRect.top = kMinHeight;
  145.  
  146.  
  147.                         /* I'm not letting the user shrink the window so */
  148.                         /* small that the title is truncated */
  149.                         /* grab the title of the window */
  150.                         GetWTitle(twindow, tempString); 
  151.                         /* make the limit the length of the title plus some */
  152.                         /* padding for the close box and zoom box */
  153.                         limitRect.left = StringWidth(tempString) + kWindowBarPad;
  154.  
  155.                         back = GrowWindow(twindow, myEventRecord.where, &limitRect);
  156.                         
  157.                         if (back) {
  158.  
  159.                             Rect sizeRect = ((WindowPtr)twindow)->portRect;
  160.  
  161.                             tempWCH = (windowCHandle)GetWRefCon(twindow);
  162.                             InvalRect(&sizeRect);
  163.                             sizeRect.top = sizeRect.bottom - kScrollBarFudge;
  164.                             sizeRect.left = sizeRect.right - kScrollBarFudge;
  165.                             EraseRect(&sizeRect);
  166.                             InvalRect(&sizeRect);
  167.                             SizeWindow(twindow, back & 0xffff, back >> kScrollBarFudge, true);
  168.                             ((*tempWCH)->sizeMe)(twindow);
  169.                         }
  170.  
  171.                         InvalRect(&twindow->portRect);
  172.                         
  173.                         break;
  174.  
  175.                     case inGoAway:
  176.  
  177.                         /* Click in Close box */
  178.  
  179.                         if (TrackGoAway(twindow, myEventRecord.where)){
  180.                             tempWCH = (windowCHandle)GetWRefCon(twindow);
  181.  
  182.                             ((*tempWCH)->closeMe)(twindow);
  183.                         }
  184.                         break;
  185.  
  186.                     case inZoomIn:
  187.                     case inZoomOut:
  188.                         /* Who's Zooming Who?  (sorry) */
  189.                         if (TrackBox(twindow, myEventRecord.where, fHit)) {
  190.                             tempWCH = (windowCHandle)GetWRefCon(twindow);
  191.                             SetPort(twindow);
  192.                             
  193.                             ZoomWindow(twindow, fHit, true);
  194.                             EraseRect(&twindow->portRect);
  195.                             InvalRect(&twindow->portRect);
  196.                             ((*tempWCH)->sizeMe)(twindow);
  197.                         }
  198.                 }
  199.  
  200.             case mouseUp:
  201.                 /* don't care */
  202.                 break;
  203.  
  204.                 /* same action for key or auto key */
  205.  
  206.             case keyDown:
  207.             case autoKey:
  208.                 if (myEventRecord.modifiers & cmdKey) {
  209.                     AdjustMenus();
  210.                     DoSelected(MenuKey(myEventRecord.message & charCodeMask));
  211.                 }
  212.                 break;
  213.  
  214.             case keyUp:
  215.                 /* don't care */
  216.                 break;
  217.  
  218.             case diskEvt:
  219.                 /* I don't do anything special for disk events, this just passes them */
  220.                 /* to a function that checks for an error on the mount */
  221.                 DoDiskEvents(myEventRecord.message);
  222.                 break;
  223.  
  224.             case activateEvt:
  225.                     if (IsMyWindow((WindowPtr)myEventRecord.message)) {
  226.                         tempWCH = (windowCHandle)GetWRefCon((WindowPtr)myEventRecord.message);
  227.                         ((*tempWCH)->activateMe)((WindowPtr)myEventRecord.message,(myEventRecord.modifiers & activeFlag));
  228.                     }
  229.                 break;
  230.  
  231.             case networkEvt:
  232.                 /* don't care */
  233.                 break;
  234.  
  235.             case driverEvt:
  236.                 /* don't care */
  237.                 break;
  238.  
  239.             case app4Evt:
  240.                 switch ((myEventRecord.message >> 24) & 0x0FF) {        /* high byte of message */
  241.                     case suspendResumeMessage:              /* suspend/resume is also an activate/deactivate */
  242.                         gInBackground = (myEventRecord.message & kResumeMask) == 0;
  243.                         if(gInBackground)
  244.                             gMySleep = kBackSleep;
  245.                             else
  246.                             gMySleep = kFrontSleep;
  247.                         break;
  248.                 }
  249.                 break;
  250.  
  251.  
  252.                 /* This dispatches high level events (AppleEvents, for example) */
  253.                 /* to our dispatch routine. This is NEW in the event loop for */
  254.                 /* System 7 */
  255.  
  256.             case kHighLevelEvent:
  257.                 DoHighLevel(&myEventRecord);
  258.                 break;
  259.  
  260.             default:
  261.                 break;
  262.  
  263.                 
  264.         }
  265.     }
  266.             while (gQuit != true);
  267.     
  268. }
  269.  
  270. /* DoDaCall opens the requested DA. It's here as a seperate routine if you'd */
  271. /* like to perform some action or just know when a DA is opened in your */
  272. /* layer. Can be handy to track memory problems when a DA is opened */
  273. /* with an Option-open */
  274. void DoDaCall(MenuHandle themenu, long theit)
  275. {
  276.     long qq;
  277.     char DAname[255];
  278.     GetItem(themenu, theit, &DAname);
  279.     qq = OpenDeskAcc(DAname);
  280. }
  281.  
  282. /* end DoDaCall */
  283.  
  284. /* DoDiskEvents just checks the error code from the disk mount, */
  285. /* and puts up the 'Format' dialog (through DIBadMount) if need be */
  286. /* You can do much more here if you care about what disks are */
  287. /* in the drive */
  288. void DoDiskEvents(long dinfo)                               /* hi word is error code, lo word is drive number */
  289. {
  290.     short hival,  tommy;
  291.     Point fredpoint =  {
  292.         40, 40
  293.     };
  294.     hival = HiWord(dinfo);   
  295.     if (hival != noErr)                                     /* something happened */ {
  296.         tommy = DIBadMount(fredpoint, dinfo);
  297.     }
  298. }
  299.  
  300. /* draws my window.  */
  301. void DrawMain(WindowPtr drawIt)
  302. {
  303.     Str32 theWords;
  304.     RgnHandle tempRgn;
  305.     short cellWide;
  306.     windowCHandle tempWCH;
  307.     Rect scratchRect;
  308.     register qq;
  309.     BeginUpdate(drawIt);
  310.     SetPort(drawIt);
  311.     /* get our extra data */
  312.     tempWCH = (windowCHandle)GetWRefCon(drawIt);
  313.  
  314.     /* update the list in this window */
  315.     LUpdate(drawIt->visRgn, (*(documentExtraDataHdl)((*tempWCH)->generalData))->displayList);
  316.  
  317.     /* now draw some lines between the cells for neatness */
  318.  
  319.     cellWide = (*(*(documentExtraDataHdl)((*tempWCH)->generalData))->displayList)->cellSize.h;
  320.  
  321.     /* draw my header information Please */ 
  322.     for (qq = 1; qq < 5; qq++) {
  323.         GetIndString(theWords, kGeneralStrings, qq);
  324.         MoveTo(cellWide * (qq - 1) + kIndent, kIndentDown);
  325.         DrawString(theWords);
  326.     }
  327.  
  328.     /* seperate routine to draw the grid lines, since I also call this from elsewhere */
  329.     ReDrawGridLines(drawIt, (*(documentExtraDataHdl)((*tempWCH)->generalData))->displayList);
  330.  
  331.     /* clip to the area the grow box is in, and draw it */
  332.     scratchRect = drawIt->portRect;
  333.     scratchRect.top = scratchRect.bottom - kScrollBarFudge;
  334.     scratchRect.left = scratchRect.right - kScrollBarFudge;
  335.     tempRgn = NewRgn();
  336.     GetClip(tempRgn);
  337.     ClipRect(&scratchRect);
  338.     DrawGrowIcon(drawIt);
  339.     SetClip(tempRgn);
  340.     DisposeRgn(tempRgn);
  341.     
  342.     EndUpdate(drawIt);
  343. }
  344.  
  345. /* my menu action taker. It returns a Boolean which I usually ignore, but it */
  346. /* mught be handy someday */
  347. /* I usually use it in an application to determine if a keystroke was accepted */
  348. /* by a menu or whether it should be passed along to any other key acceptors */
  349. Boolean DoSelected(long val)
  350. {
  351.     short loval, hival;
  352.     Boolean returnVal = false;
  353.     loval = LoWord(val);
  354.     hival = HiWord(val);
  355.     
  356.     switch (hival) {                                        /* switch off the menu number selected */
  357.         case kAppleMenu:                                    /* Apple menu */
  358.             if (loval != kAboutItem) {                               /* if this was not About, it's a DA */
  359.                 DoDaCall(GetMHandle(kAppleMenu), loval);
  360.             } else {
  361.                 Alert(kAboutBox, nil);                      /* do about box */
  362.             }
  363.             returnVal = true;
  364.             break;
  365.         case kFileMenu:                                     /* File menu */
  366.             switch (loval) {
  367.                 case kNewItem:
  368.                     AddNewWindow(kDocWindowResID);
  369.                     break;
  370.                 case kCloseItem:
  371.                     CloseTheWindow(FrontWindow());
  372.                     break;
  373.                     break;
  374.                 case kQuitItem:
  375.                     gQuit = true;                           /* only item */
  376.                     returnVal = true;
  377.                     break;
  378.                 default:
  379.                     break;
  380.             }
  381.             break;
  382.             
  383.         case kEditMenu:
  384.             /* edit menu junk */
  385.             /* don't care */
  386.             switch (loval) {
  387.             default:
  388.                 break;
  389.             }
  390.             break;
  391.         case kToolsMenu:
  392.             /* add all your test stuff here */
  393.             switch (loval) {
  394.                 case kGetResInfoItem:
  395.                     GetAResourceType(FrontWindow());
  396.                     
  397.                     break;
  398.                 default:
  399.                     break;
  400.             }
  401.             break;
  402.  
  403.         case kHMHelpMenuID:                                 /* Defined in Balloons.h */
  404.             /* I only care about this item. If anything else is returned here, I don't know what */
  405.             /* it is, so I leave it alone. Remember, the Help Manager chapter says that */
  406.             /* Apple reserves the right to add and change things in the Help menu */
  407.             if (loval == gHelpItem)
  408.                 SampleHelpDialog();
  409.             break;
  410.             
  411.     }
  412.     /* dim the hilit menu title */
  413.     HiliteMenu(0);
  414.     return(returnVal);
  415. }
  416.  
  417. /* handles clicks in my windows */
  418. void DoDocumentClick(WindowPtr theWindow)
  419. {
  420.     windowCHandle tempWCH = (windowCHandle)GetWRefCon(theWindow);
  421.     Point thePoint;
  422.     GetMouse(&thePoint);
  423.     /* since the only clickable thing that will get to here is the List, pass */
  424.     /* off to the list manager */
  425.     /* I'm passing nil for the modifiers, since selections and ranges don't */
  426.     /* really mean anything in this sample */
  427.     LClick(thePoint, nil, (*(documentExtraDataHdl)((*tempWCH)->generalData))->displayList);
  428.  
  429.     /* if they clicked, then the grid lines may have to be updated */
  430.     /* since they could have scrolled the list.  I could check for that, but */
  431.     /* it doesn't cause any problems just to redraw */
  432.     ReDrawGridLines(theWindow, (*(documentExtraDataHdl)((*tempWCH)->generalData))->displayList);
  433. }
  434.  
  435. /* I'm not doing error handling in this sample for clarities sake, you should. Hah, */
  436. /* easy for me to say, huh? */
  437. void DoHighLevel(EventRecord *AERecord)
  438. {
  439.     /* this passes off to my AppleEvent handlers automatically. */
  440.     /* If I don't have a handler for this event, then this function */
  441.     /* returns an error */
  442.     AEProcessAppleEvent(AERecord);
  443.     
  444. }
  445.  
  446. /* end DoHighLevel */
  447.  
  448. /* This is the standard Open Application event. */
  449. pascal OSErr AEOpenHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  450. {
  451.     WindowPtr myWindow;
  452.  
  453. #pragma unused (messagein,reply,refIn)
  454.     /* we of course don't do anything here in this simple app */
  455.     /* except open our window */
  456.     myWindow = AddNewWindow(kDocWindowResID);
  457.     
  458.     return(noErr);
  459. }
  460.  
  461. /* end AEOpenHandler */
  462.  
  463. /* Open Doc, opens our documents. Remember, this can happen at application start AND */
  464. /* anytime else. If your app is up and running and the user goes to the desktop, hilites one */
  465. /* of your files, and double-clicks or selects Open from the finder File menu this event */
  466. /* handler will get called. Which means you don't do any initialization of globals here, or */
  467. /* anything else except open then doc. */
  468. /* SO-- Do NOT assume that you are at app start time in this */
  469. /* routine, or bad things will surely happen to you. */
  470.  
  471. pascal OSErr AEOpenDocHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  472. {
  473. #pragma unused (messagein,refIn,reply)
  474.     /* we of course don't do anything here */
  475.     /* since I don't have any documents */
  476.     return(errAEEventNotHandled);                           /* we have no docs, so no odoc events should come to us */
  477. }
  478.  
  479. pascal OSErr AEPrintHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  480. {                                                           /* no printing handler in yet, so we'll ignore this */
  481.     /* the operation is functionally identical to the ODOC event, with the additon */
  482.     /* of calling your print routine. */
  483. #pragma unused (messagein,refIn,reply)
  484.     /* we of course don't do anything here */
  485.     return(errAEEventNotHandled);                           /* we have no docs, so no pdoc events should come to us */
  486. }
  487.  
  488. /* Standard Quit event handler, to handle a Quit event from the Finder, for example. */
  489. /* ••••• DO NOT CALL EXITTOSHELL HERE ••••• or you will never have a happy life. */
  490. /* OK, it's a few months after I wrote that comment, and I've seen a lot of code */
  491. /* come through DTS that calls ExitToShell from quit handlers. Let me explain... */
  492. /* When an AppleEvent Handler is called (like this quit handler) you are ALMOST */
  493. /* 100% in your application world. A5 is right, you can call any toolbox function, */
  494. /* you can call your own routines, everything _seems_ like you are in complete */
  495. /* control. Well, almost but not quite. The routine has been dispatch to from the */
  496. /* AppleEvent Manager's space, so you _must_ return to that at some point! */
  497. /* Which is why you can't call ETS from here. When you call ExitToShell from an */
  498. /* AE Handler, the most likely thing that happens is the FInder quits, and your */
  499. /* application keeps running. Which ain't what you want, y'know? */
  500. /* so, DON'T CALL EXITTOSHELL FROM AN APPLEEVENT HANDLER!!!!!!!!!!!!!! */
  501. pascal OSErr AEQuitHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  502. {
  503. #pragma unused (messagein,refIn,reply)
  504.     gQuit = true;
  505.     return(noErr);
  506. }
  507.  
  508. /* This is my sample help dialog. Does not do anything, expand as you need */
  509. void SampleHelpDialog(void)
  510. {
  511.     DialogPtr tdial = GetNewDialog(kSampHelp, nil, (WindowPtr)-1);
  512.     short itemhit = 0;
  513.     gExtraDialogFilter = nil;                               /* no extras this time */
  514.     while (itemhit != ok) {
  515.         
  516.         ModalDialog((ModalFilterProcPtr)standardDialogFilter, &itemhit);
  517.     }
  518.     DisposDialog(tdial);
  519. }
  520.  
  521.  
  522. #pragma segment Initialize
  523. void InitalizeApp(void)
  524. {
  525.     Handle myMenu;
  526.     MenuHandle helpHandle, appleMenuHandle;
  527.     StringHandle helpString;
  528.     short count;
  529.     long vers;
  530.     /* move my applLimit to the end of the space I can grow to */
  531.     MaxApplZone();
  532.     
  533.     /* Init the Managers */
  534.     InitGraf((Ptr)&qd.thePort);
  535.     InitFonts();
  536.     InitWindows();
  537.     InitMenus();
  538.     TEInit();
  539.     InitDialogs(nil);
  540.     InitCursor();
  541.     /* Check system version */
  542.     Gestalt(gestaltSystemVersion, &vers);
  543.     vers = (vers >> 8) & 0xf;                               /* shift result over and mask out major version number */
  544.     if (vers < 7) {
  545.         StopAlert(kBadSystem, nil);
  546.         ExitToShell();
  547.     }
  548.     
  549.     /* Init and install my AppleEvent handlers */
  550.     InitAEStuff();
  551.     
  552.     /* set up my menu junk */
  553.     myMenu = GetNewMBar(kMBarID);
  554.     SetMenuBar(myMenu);
  555.     appleMenuHandle = GetMHandle(kAppleMenu);
  556.     AddResMenu(appleMenuHandle, 'DRVR');
  557.     
  558.     /* now install my Help menu item in the Help Manager's menu */
  559.     HMGetHelpMenuHandle(&helpHandle);                       /* Get the Hlpe menu handle */
  560.     count = CountMItems(helpHandle);                        /* How many items are there? */
  561.     helpString = GetString(kHelpString);                    /* get my help string */
  562.     HLock((Handle)helpString);
  563.     InsMenuItem(helpHandle, (Ptr)*helpString, count + 1);       /* insert my item in the Help menu */
  564.     ReleaseResource((Handle)kHelpString);
  565.     gHelpItem = CountMItems(helpHandle);                    /* The number of the item */
  566.     
  567.     DrawMenuBar();
  568.     GetCurrentProcess(&gOurSN);                             /* Get our process serial number for later use, if needed */
  569.     
  570. }
  571.  
  572. /* InitAEStuff installs my appleevent handlers */
  573. void InitAEStuff(void)
  574. {
  575.     AEinstalls HandlersToInstall[] =  { {
  576.             kCoreEventClass, kAEOpenApplication, AEOpenHandler
  577.         },  {
  578.             kCoreEventClass, kAEOpenDocuments, AEOpenDocHandler
  579.         },  {
  580.             kCoreEventClass, kAEQuitApplication, AEQuitHandler
  581.         },  {
  582.             kCoreEventClass, kAEPrintDocuments, AEPrintHandler
  583.         }, 
  584.         /* The above are the four required AppleEvents. */ {
  585.             kCoreEventClass, kAEAnswer, AEAnswerHandler
  586.         }
  587.     };
  588.     
  589.     OSErr aevtErr = noErr;
  590.     long aLong = 0;
  591.     Boolean gHasAppleEvents = false;
  592.     /* Check this machine for AppleEvents. If they are not here (ie not 7.0)
  593.     * then we exit */
  594.     gHasAppleEvents = (Gestalt(gestaltAppleEventsAttr, &aLong) == noErr);
  595.     /* The following series of calls installs all our AppleEvent Handlers.
  596.     * These handlers are added to the application event handler list that 
  597.     * the AppleEvent manager maintains. So, whenever an AppleEvent happens
  598.     * and we call AEProcessEvent, the AppleEvent manager will check our
  599.     * list of handlers and dispatch to it if there is one.
  600.     */
  601.     if (gHasAppleEvents) {
  602.         register qq;
  603.         for (qq = 0; qq < ((sizeof(HandlersToInstall) / sizeof(AEinstalls))); qq++) {
  604.             aevtErr = AEInstallEventHandler(HandlersToInstall[qq].theClass, HandlersToInstall[qq].theEvent,
  605.                                             HandlersToInstall[qq].theProc, 0, false);
  606.             if (aevtErr) {
  607.                 ExitToShell();                              /* just fail, baby */
  608.             }
  609.         }
  610.     } else {
  611.         ExitToShell();
  612.     }
  613. }
  614.  
  615. /* end InitAEStuff */
  616.  
  617.  
  618. #pragma segment Main
  619. /* adds a new window to my environment */
  620.  
  621. WindowPtr AddNewWindow(short theID)
  622. {
  623.     /* the following rects and cell are for list creation */
  624.     Rect viewRect;
  625.     
  626.     Rect dataBRect =  {                                     /* three columns */
  627.         0, 0, 0, 4
  628.     };
  629.     Cell cSize =  {
  630.         0, 0
  631.     };                                                      /* default cell size */
  632.     
  633.     windowCHandle setControls;
  634.     WindowPtr tempWP;
  635.     short cnt = 0;
  636.     /* get a new window */
  637.     tempWP = GetNewWindow(theID, 0, (WindowPtr)-1);         
  638.     
  639.     /* mark it as my document window */
  640.     ((WindowPeek)tempWP)->windowKind = kMyDocumentWindow;       
  641.     
  642.      /* add our control structure to it */
  643.     setControls = (windowCHandle)NewHandleClear(sizeof(windowControl));    
  644.     
  645.      /* stop stuffing refCon directly <ckh 1.0.3> */
  646.     SetWRefCon(tempWP, (long)setControls);                 
  647.  
  648.     /* add a unique ID */
  649.     AddWindowID(tempWP);
  650.     
  651.     HLock((Handle)setControls);                             /* lock it down while we fill it*/
  652.     
  653.     /* add pointers to our procedures for drawing, saving, and closing */
  654.     /* This way, all I need is one dispatch point for drawing, closing */
  655.     /* or whatever, I don't have to case off the window kind to go to the */
  656.     /* correct routine. Kinda like object-oriented programming, but I won't */
  657.     /* admit that. */
  658.     
  659.     (*setControls)->drawMe = DrawMain;
  660.     (*setControls)->clickMe = DoDocumentClick;
  661.     (*setControls)->sizeMe = SizeMain;
  662.     (*setControls)->closeMe = CloseTheWindow;
  663.     (*setControls)->activateMe = ActivateMain;
  664.     
  665.     /* in this sample, this handle will simply contain a list */
  666.     /* to display in the window */
  667.     (*setControls)->generalData = NewHandle(sizeof(documentExtraData));
  668.     
  669.     /* I'nm going to store my ListHandle in generalData */
  670.     HLock((*setControls)->generalData);
  671.     viewRect = tempWP->portRect;
  672.     viewRect.top += kTopLineHeight;                                     /* room for some text at the top */
  673.     viewRect.bottom -= kScrollBarFudge;                                  /* romm for list scroll bars */
  674.     viewRect.right -= kScrollBarFudge;
  675.     
  676.     (*(documentExtraDataHdl)((*setControls)->generalData))->displayList = LNew(&viewRect, &dataBRect, cSize, nil, tempWP, true,
  677.                                                                                false, true, true);
  678.     
  679.     LActivate(true, (*(documentExtraDataHdl)((*setControls)->generalData))->displayList);
  680.     LDoDraw(true, (*(documentExtraDataHdl)((*setControls)->generalData))->displayList);
  681.     
  682.     HUnlock((*setControls)->generalData);
  683.     HUnlock((Handle)setControls);   
  684.     
  685.     return(tempWP);
  686. }
  687.  
  688. /* handle a resize, which means resizing the list in this example  */
  689. void SizeMain(WindowPtr theWindow)
  690. {
  691.     WindowPtr tempWP;
  692.     windowCHandle tempWCH = (windowCHandle)GetWRefCon(theWindow);
  693.     
  694.     GetPort(&tempWP);
  695.     InvalRect(&theWindow->portRect);
  696.     
  697.     /* change the list size to the new size for the winder */
  698.     /* make sure to leave border space for the scroll bars */
  699.     LSize((theWindow->portRect.right - theWindow->portRect.left) - kScrollBarFudge,
  700.           ((theWindow->portRect.bottom - theWindow->portRect.top) - kScrollBarFudge) - kTopLineHeight,
  701.           (*(documentExtraDataHdl)((*tempWCH)->generalData))->displayList);
  702.     SetPort(tempWP);
  703. }
  704.  
  705. /* see if the window in question is really mine */
  706. Boolean IsMyWindow(WindowPtr theWind)
  707. {
  708.     return(((WindowPeek)theWind)->windowKind == kMyDocumentWindow);
  709. }
  710.  
  711.  
  712. /* Here I'm looking for MungeDeamon. */
  713. /* First I look to see if the process is already running. */
  714. /* If it's not, I use PBCatSearch to find it, and launch it */
  715. /* if I find it */
  716. OSErr FindOrLaunchAProcess(OSType theSig, AEDesc *theAddress)
  717. {
  718.     OSErr myError;
  719.     
  720.     /* let people know I'm busy looking */
  721.     DialogPtr search = GetNewDialog(kSearchDialog, nil, (WindowPtr)-1);
  722.     
  723.     /* param block for cat search */
  724.     CSParamPtr csBlockPtr = NewPtrClear(sizeof(CSParam));
  725.  
  726.     LaunchParamBlockRec launchThis;
  727.     long dirIDUnused;
  728.     Str32 nulString = "\p";
  729.  
  730.     DrawDialog(search);
  731.     /* first just see if it's already running */
  732.     if (noErr == FindAProcess(theSig, &launchThis.launchProcessSN)) {
  733.         /* it was running */
  734.         /* make an address desc from this PSN */
  735.         myError = AECreateDesc(typeProcessSerialNumber, (Ptr)&launchThis.launchProcessSN, sizeof(ProcessSerialNumber),
  736.                                theAddress);
  737.         
  738.     } else {
  739.     /* we couldn't find it in the process list, look for it on the volume and */
  740.     /* launch it if found */
  741.         /* initialize the parameter block */
  742.  
  743.         /* • NOTE: I'm just searching the default volume here! */
  744.         /* you might want to search all the volumes. */
  745.         if (csBlockPtr) {
  746.             csBlockPtr->ioSearchInfo1 = (CInfoPBPtr)NewPtrClear(sizeof(CInfoPBRec));
  747.             csBlockPtr->ioSearchInfo2 = (CInfoPBPtr)NewPtrClear(sizeof(CInfoPBRec));
  748.             if (csBlockPtr->ioSearchInfo1 && csBlockPtr->ioSearchInfo2) {
  749.  
  750.             /* only looking for 1 */
  751.                 csBlockPtr->ioMatchPtr = (FSSpecPtr)NewPtrClear(sizeof(FSSpec) * 1);        
  752.  
  753.                 if (csBlockPtr->ioMatchPtr) {
  754.                     /* Now see if we can create an optimization buffer */
  755.                     csBlockPtr->ioOptBuffer = NewPtr(2048);
  756.                     if (csBlockPtr->ioOptBuffer)
  757.                         csBlockPtr->ioOptBufSize = 2048;
  758.                     else
  759.                         csBlockPtr->ioOptBufSize = 0;       /* no buffer, sorry */
  760.                     csBlockPtr->ioReqMatchCount = 1;
  761.                     csBlockPtr->ioSearchTime = 0;           /* no timeout */
  762.                 }
  763.             }
  764.         }
  765.  
  766.         HGetVol(nil, &csBlockPtr->ioVRefNum, &dirIDUnused);     /* get default volume for search */
  767.  
  768.         csBlockPtr->ioSearchInfo1->hFileInfo.ioNamePtr = nil;
  769.         csBlockPtr->ioSearchInfo2->hFileInfo.ioNamePtr = nil;
  770.         csBlockPtr->ioSearchInfo1->hFileInfo.ioFlFndrInfo.fdCreator = theSig;
  771.         csBlockPtr->ioSearchInfo1->hFileInfo.ioFlFndrInfo.fdType = 'APPL';
  772.         csBlockPtr->ioSearchBits = fsSBFlFndrInfo;
  773.         csBlockPtr->ioSearchInfo2->hFileInfo.ioFlFndrInfo.fdCreator = 0xFFFFFFFF;
  774.         csBlockPtr->ioSearchInfo2->hFileInfo.ioFlFndrInfo.fdType = 0xFFFFFFFF;
  775.         
  776.         myError = PBCatSearch(csBlockPtr, false);           /* search sync */
  777.  
  778.         if (myError == noErr && csBlockPtr->ioActMatchCount != 0) {
  779.             /* we found it, so launch it */
  780.             launchThis.reserved1 = nil;
  781.             launchThis.reserved2 = nil;
  782.             launchThis.launchPreferredSize = nil;
  783.             launchThis.launchMinimumSize = nil;
  784.             launchThis.launchAvailableSize = nil;
  785.             launchThis.launchAppParameters = nil;
  786.             launchThis.launchBlockID = extendedBlock;
  787.             launchThis.launchEPBLength = extendedBlockLen;
  788.             launchThis.launchFileFlags = nil;
  789.             launchThis.launchControlFlags = launchContinue + launchNoFileFlags + launchDontSwitch;
  790.             launchThis.launchAppSpec = &csBlockPtr->ioMatchPtr[0];
  791.             myError = LaunchApplication(&launchThis);
  792.             if (myError == noErr) {
  793.                 /* it launched fine. we can use the PSN to make a target */
  794.                 AECreateDesc(typeProcessSerialNumber, (Ptr)&launchThis.launchProcessSN, sizeof(ProcessSerialNumber), theAddress);
  795.                 
  796.             }
  797.         }
  798.         
  799.         /* no matter what happened, kill the memory we had allocated */
  800.         if (csBlockPtr) {
  801.             if (csBlockPtr->ioSearchInfo1)
  802.                 DisposPtr((Ptr)csBlockPtr->ioSearchInfo1);
  803.             if (csBlockPtr->ioSearchInfo2)
  804.                 DisposPtr((Ptr)csBlockPtr->ioSearchInfo2);
  805.             if (csBlockPtr->ioMatchPtr)
  806.                 DisposPtr((Ptr)csBlockPtr->ioMatchPtr);
  807.             if (csBlockPtr->ioOptBuffer)
  808.                 DisposPtr((Ptr)csBlockPtr->ioOptBuffer);
  809.             DisposPtr((Ptr)csBlockPtr);
  810.         }
  811.     }                                                       /* catsearch section end */
  812.     DisposDialog(search);
  813.     return(myError);
  814. }
  815.  
  816. /* a litte routine to walk the process list looking for a specific application */
  817. /* signature */
  818. OSErr FindAProcess(OSType creatorToFind, ProcessSerialNumberPtr processSN)
  819. {
  820.     ProcessInfoRec infoRecToFill;
  821.     FSSpec tempSpec;
  822.     Str255 tempName;
  823.     OSErr myErr = noErr;
  824.     processSN->lowLongOfPSN = kNoProcess;
  825.     processSN->highLongOfPSN = kNoProcess;
  826.     infoRecToFill.processName = &tempName;
  827.     infoRecToFill.processAppSpec = &tempSpec;
  828.     do {
  829.     /* start at the beginning of the list, walk through all the processes */
  830.     /* until we find it or error out at the end of the list */
  831.         myErr = GetNextProcess(processSN);
  832.         if (myErr == noErr)
  833.             GetProcessInformation(processSN, &infoRecToFill);
  834.         if (infoRecToFill.processSignature == creatorToFind)
  835.             break;
  836.     }
  837.             while (myErr == noErr);
  838.     
  839.     return(myErr);
  840. }
  841.  
  842. /* This is an AppleEvent Idle function. It can be passed to AEInteractWithUser */
  843. /* or AESend. */
  844. /* What it does is this; */
  845. /* If some AppleEvent thing is taking a really long time, the AppleEvent manager */
  846. /* will call WaitNextEvent FOR you (yeah, yeah, only one event loop per app, oh well) */
  847. /* and give you a result (limited) if you need to do something. That something */
  848. /* will only be an update,activate,OSevent, or null event */
  849. pascal Boolean CommonIdleFunction(EventRecord *whatEvent, long *sleeping, RgnHandle *mouseRgn)
  850. {
  851. #pragma unused (sleeping,mouseRgn)
  852.     extern Boolean gInBackground;
  853.     
  854.     extern RgnHandle mousergn;
  855.     switch (whatEvent->what) {
  856.         case updateEvt:
  857.             if (IsMyWindow((WindowPtr)whatEvent->message)) {
  858.                 windowCHandle tempWCH = (windowCHandle)GetWRefCon((WindowPtr)whatEvent->message);
  859.                 (ProcPtr)((*tempWCH)->drawMe)((WindowPtr)whatEvent->message);
  860.             }
  861.             break;
  862.         case activateEvt:
  863.             
  864.             break;
  865.         case app4Evt:                                       /* or kOSEvent, I'm old fashioned */
  866.             switch ((whatEvent->message >> 24) & 0x0FF) {       /* high byte of message */
  867.                 case suspendResumeMessage:                  /* suspend/resume is also an activate/deactivate */
  868.                     gInBackground = (whatEvent->message & kResumeMask) == 0;
  869.                     
  870.                     break;
  871.             }
  872.             break;
  873.         case nullEvent:
  874.             break;
  875.             
  876.     }
  877.     return(false);                                          /* If it takes for-ever I will wait, for you... Sorry. */
  878. }
  879.  
  880. /* GetAResourceType asks for the resource type to get info on */
  881. void GetAResourceType(WindowPtr theWindow)
  882. {
  883.     Rect tempRect;
  884.     short tempItem;
  885.     Handle tempHandle;
  886.     Str15 myStr;
  887.     ResType theType;
  888.     short hitItem;
  889.     
  890.     DialogPtr myDialog = GetNewDialog(kResTypeDialog, nil, (WindowPtr)-1);
  891.     
  892.     /* New System 7 dialog manager calls, see tech note #304 */
  893.     /* interface to these calls is in OtherResInfo.protos.h */
  894.     SetDialogDefaultItem(myDialog, ok);
  895.     SetDialogCancelItem(myDialog, cancel);
  896.     SetDialogTracksCursor(myDialog, true);
  897.     
  898.     do {
  899.         /* since I'm doing some restriction, I have to add an additional filtering */
  900.         /* step, see the standardDialogFilter for how this is used */
  901.         gExtraDialogFilter = filterIt;
  902.         
  903.         ModalDialog((ModalFilterProcPtr)standardDialogFilter, &hitItem);
  904.         if (hitItem == kResTypeQuitCheck)
  905.             SetCtlValue(SnatchHandle(myDialog, hitItem), (GetCtlValue(SnatchHandle(myDialog, hitItem)) ? 0 : 1));
  906.     }
  907.             while (hitItem != ok && hitItem != cancel);
  908.     
  909.     if (hitItem == ok) {
  910.         
  911.         /* get the type and hammer it */
  912.         GetDItem(myDialog, kResTypeEditLine, &tempItem, &tempHandle, &tempRect);
  913.         GetIText(tempHandle, myStr);
  914.         
  915.         /* make sure there are 4 characters here, please */
  916.         if (myStr[0] == 4) {
  917.             Boolean theQuitter;
  918.             BlockMove((Ptr)&myStr[1], (Ptr)&theType, sizeof(theType));
  919.             
  920.             /* also get the quit value  */
  921.             theQuitter = GetCtlValue(SnatchHandle(myDialog, kResTypeQuitCheck));
  922.             DisposDialog(myDialog);
  923.             /* Send this info off to my event sender, please */
  924.             
  925.             SendInfoEvent(theType, theQuitter, theWindow);
  926.         }
  927.     } else {
  928.         DisposDialog(myDialog);
  929.         
  930.     }
  931. }
  932.  
  933.  
  934. /* Some dialog filtering things */
  935. /* TabRetEsc toggles the cancel or OK button for keystrokes, and */
  936. /* treats a Tab press as selecting the whole edit line contents */
  937.  
  938. Boolean TabRetEsc(DialogPtr inputDialog, EventRecord *myDialogEvent, short *theDialogItem)
  939. {
  940.     Boolean returnValue = false;
  941.     long tilticks;
  942.     WindowPtr tempWindowPtr;
  943.     char theKey = myDialogEvent->message &charCodeMask;
  944.     GetPort(&tempWindowPtr);
  945.     SetPort(inputDialog);
  946.     switch (theKey) {
  947.         case kReturnKey:
  948.         case kEnterKey:                                     /* enter key */
  949.             /* This filters for Return or Enter as item 1, and Esc as item 2 */
  950.             *theDialogItem = ok;                            /* change whatever the current item is to the OK item */
  951.             /* now we need to invert the button */
  952.             HiliteControl(SnatchHandle(inputDialog, ok), inButton);
  953.             Delay(8, &tilticks);                            /* wait about 8 ticks so they can see it */
  954.             HiliteControl(SnatchHandle(inputDialog, ok), false);
  955.             returnValue = true;
  956.             break;
  957.             /* This filters the escape key as the same as item 2 (the canx button, usually ) */
  958.         case kEscKey:
  959.             *theDialogItem = cancel;
  960.             HiliteControl(SnatchHandle(inputDialog, cancel), inButton);
  961.             Delay(8, &tilticks);                            /* wait about 8 ticks so they can see it */
  962.             HiliteControl(SnatchHandle(inputDialog, cancel), false);
  963.             returnValue = true;
  964.             break;
  965.         case kTabKey:
  966.             /* I'm filtering the tab key here so a tab selects all the */
  967.             /* text in the edit line, as a convinience */
  968.             SelIText(inputDialog, kResTypeEditLine, 0, 5);
  969.             returnValue = true;                             /* don't allow edit line swaps */
  970.             break;
  971.     }
  972.     SetPort(tempWindowPtr);
  973.     
  974.     return(returnValue);
  975.     
  976. }
  977.  
  978. /* Main dialog filter */
  979. pascal Boolean filterIt(DialogPtr inputDialog, EventRecord *myDialogEvent, short *theDialogItem)
  980. {
  981.     
  982.     Boolean returnVal = false;
  983.     ModalFilterProcPtr theModalProc;
  984.     char theKey;
  985.     Rect tempRect;
  986.     short tempItem;
  987.     Handle tempHandle;
  988.     char tempKey;
  989.     Str255 myStr;
  990.     long offset;
  991.     short selection;
  992.     long scrapLen;
  993.     short resultLen;
  994.     Boolean wasAKey = false;
  995.     if (myDialogEvent->what == updateEvt && myDialogEvent->message != inputDialog) {
  996.         /* May be a pending update event for another window, handle it so */
  997.         /* other layers get time */
  998.         windowCHandle tempWCH;
  999.         WindowPtr theWindow = (WindowPtr)myDialogEvent->message;
  1000.         /* draw my window if it's really mine */
  1001.         if (((WindowPeek)theWindow)->windowKind == kMyDocumentWindow) {
  1002.             tempWCH = (windowCHandle)GetWRefCon(theWindow);
  1003.             (ProcPtr)((*tempWCH)->drawMe)((WindowPtr)theWindow);
  1004.             
  1005.             *theDialogItem = 0;
  1006.             returnVal = true;
  1007.         }
  1008.     } else {
  1009.         wasAKey = (myDialogEvent->what == keyDown) || (myDialogEvent->what == autoKey);
  1010.         
  1011.         if ((wasAKey)) {
  1012.             /* first check on the Big Three, tab, return, and escape */
  1013.             if (!(returnVal = TabRetEsc(inputDialog, myDialogEvent, theDialogItem))) {
  1014.                 
  1015.                 /* not one of those, see if this keystroke will fit */
  1016.                 /* in the edit line (restricted to 4 characters for a ResType) */
  1017.                 /* Here I'm seeing if anything is selected, and getting the length */
  1018.                 /* of the desk scrap in case the user presses */
  1019.                 /* Copy or Paste keys */
  1020.                 
  1021.                 selection = HasSelectionRange((DialogPeek)inputDialog);
  1022.                 scrapLen = GetScrap(nil, 'TEXT', &offset);
  1023.                 
  1024.                 GetDItem(inputDialog, kResTypeEditLine, &tempItem, &tempHandle, &tempRect);
  1025.                 GetIText(tempHandle, myStr);
  1026.                 
  1027.                 /* calculate the result of adding the scrap to the current record.We use */
  1028.                 /* this in a few places here */
  1029.                 resultLen = myStr[0] + (scrapLen - selection);
  1030.                 
  1031.                 theKey = myDialogEvent->message & charCodeMask;
  1032.                 tempKey = theKey;
  1033.                 if (tempKey >= 0x61 && tempKey <= 0x7a)
  1034.                     tempKey -= 0x20;
  1035.                 
  1036.                 if (myStr[0] > 3) {                         /* over 4, see what it is */
  1037.                     
  1038.                     if (IsEditKey(theKey, myDialogEvent->modifiers)) {
  1039.                         /* it was an editing key, but it MAY be a command-V. */
  1040.                         /* If it's a command-V then we won't allow it UNLESS */
  1041.                         /* there is a slection range AND the new data won't overrun things */
  1042.                         if ((tempKey == 'V') && (myDialogEvent->modifiers & cmdKey)) {
  1043.                             
  1044.                             /* this was a paste.check selection range and scrap len*/
  1045.                             if (resultLen < 4) {
  1046.                                 returnVal = false;          /* net result is4 or less */
  1047.                             } else {
  1048.                                 SysBeep(1);
  1049.                                 returnVal = true;
  1050.                             }
  1051.                         } else {
  1052.                             returnVal = false;              /* don't filter out editing keys */
  1053.                         }
  1054.                     } else {
  1055.                         /* One more check (this can get complicated, huh?) */
  1056.                         /* We now look to see if there is a selection range.If there */
  1057.                         /* is a range of 1 or more characters, then the one character they are entering */
  1058.                         /* now will replace that, and we'll end up with _less_ than 4 (or equal) */
  1059.                         /* to do this, we have to get the TERecord out of the dialog.*/
  1060.                         /* I'm going to do this in a seperate function */
  1061.                         if (selection == nil) {
  1062.                             SysBeep(1);                     /* complain a little */
  1063.                             returnVal = true;               /* tell the dialog manager that we handled this already and */
  1064.                             /* it doesn't have to, so the keystroke will _not_ get */
  1065.                             /* added to the edit line */
  1066.                         }
  1067.                     }
  1068.                 } else {
  1069.                     /* even if we're less than 4 currently, a Command-V (paste) could put us over */
  1070.                     /* so check it out */
  1071.                     
  1072.                     if ((tempKey == 'V') && (myDialogEvent->modifiers & cmdKey)) {
  1073.                         
  1074.                         /* Gettting the scrap with a nil handle, which does not give us data, just */
  1075.                         /* returns the size */
  1076.                         if (resultLen > 3) {
  1077.                             SysBeep(1);                     /* complain a little */
  1078.                             returnVal = true;               /* tell the dialog manager that we handled this already and */
  1079.                             
  1080.                         }
  1081.                     }
  1082.                 }
  1083.             }
  1084.         }
  1085.     }
  1086.     if (!returnVal) {
  1087.         
  1088.         OSErr myErr = GetStdFilterProc(&theModalProc);
  1089.         if (myErr == noErr)
  1090.             returnVal = theModalProc(inputDialog, myDialogEvent, theDialogItem);
  1091.     }
  1092.     return(returnVal);
  1093. }
  1094.  
  1095. /* a little routine to see if there is text selected in the edit line, I need */
  1096. /* this to determine if a new keystroke will fit. */
  1097. /* An example; */
  1098. /* If I'm restricting to 4 characters, and there are already 4 characters in the */
  1099. /* edit line, a simple check would refuse any more keystrokes.  */
  1100. /* BUT, if there is a selection range, the new keystroke is actually */
  1101. /* going to replace some of the characters, so it should in fact be accepted */
  1102.  
  1103. short HasSelectionRange(DialogPeek inputDialog)
  1104. {
  1105.     TEHandle theTERecord = inputDialog->textH;
  1106.     short returnVal = (*theTERecord)->selEnd -(*theTERecord)->selStart;
  1107.     
  1108.     return(returnVal);
  1109. }
  1110.  
  1111. /* end HasSelectionRange */
  1112.  
  1113. /* a little utility to see if the current key is an edit-type key */
  1114. Boolean IsEditKey(char theKey, short modifiers)
  1115. {
  1116.     register qq;
  1117.     Boolean returnVal = false;
  1118.     char editChars[] =  {
  1119.         kLeftArrow, kUpArrow, kRightArrow, kDownArrow, kBackSpace, kEscKey
  1120.     };
  1121.     char commandEdits[] =  {
  1122.         'C', 'V', 'P'
  1123.     };
  1124.     for (qq = 0; qq < sizeof(editChars) / sizeof(char); qq++) {
  1125.         if (theKey == editChars[qq])
  1126.             returnVal = true;
  1127.     }
  1128.     if (returnVal != true && (modifiers & cmdKey)) {
  1129.         /* check for XCP */
  1130.         /* Do you want me to use 'toupper()'?What! And link in all of StdLib! aggggg */
  1131.         if (theKey >= 0x61 && theKey <= 0x7a)
  1132.             theKey -= 0x20;
  1133.         for (qq = 0; qq < sizeof(commandEdits) / sizeof(char); qq++) {
  1134.             if (theKey == commandEdits[qq])
  1135.                 returnVal = true;
  1136.         }
  1137.     }
  1138.     return(returnVal);
  1139. }
  1140.  
  1141. /* end IsEditKey */
  1142.  
  1143. /* Gets the ControlHandle for the item you want in the dialog box thebox.*/
  1144. /* Handy for setting checkboxes and radio buttons */
  1145. ControlHandle SnatchHandle(DialogPtr thebox, short theGetItem)
  1146. {
  1147.     short itemtype;
  1148.     Rect itemrect;
  1149.     Handle thandle;
  1150.     
  1151.     GetDItem(thebox, theGetItem, &itemtype, &thandle, &itemrect);
  1152.     return((ControlHandle)thandle);
  1153. }
  1154.  
  1155. /* end SnatchHandle */
  1156.  
  1157. /* SendInfoEvent is where we find and send an event to our backgrounder. */
  1158. /* We are specifing kAEQueueReply, so we will not get a reply at this time */
  1159. /* it will come to us through our regular event loop */
  1160. void SendInfoEvent(ResType theType, Boolean quit, WindowPtr theWindow)
  1161. {
  1162.     StandardFileReply theReply;
  1163.     OSErr myErr = noErr;
  1164.     Point myPoint =  {
  1165.         -1, -1
  1166.     };
  1167.     AliasHandle theAlias;
  1168.     windowCHandle tempWCH = (windowCHandle)GetWRefCon(theWindow);
  1169.     
  1170.     AppleEvent theEvent;
  1171.     AEDesc tempDesc;
  1172.     AEDesc theAddress;
  1173.     SFTypeList myList =  {
  1174.         'APPL'
  1175.     };
  1176.     /* I'm using custom get file ONLY because I want to have a different */
  1177.     /* dialog arrangement */
  1178.     /* I'm not doing anything else with the thing */
  1179.     CustomGetFile(nil, 1, &myList, &theReply, 4000, myPoint, nil, nil, nil, nil, nil);
  1180.     
  1181.     if (theReply.sfGood) {
  1182.  
  1183.         /* I'm changing the name of the window to reflect this file name now, just for grins */
  1184.         SetWTitle(theWindow, &theReply.sfFile.name);
  1185.  
  1186.         myErr = NewAlias(nil, &theReply.sfFile, &theAlias);
  1187.  
  1188.         if (myErr == noErr) {
  1189.  
  1190.             /* make an event and send to our friend */
  1191.             myErr = FindOrLaunchAProcess(kMungeDeamonCreator, &theAddress);
  1192.  
  1193.             if (myErr == noErr) {
  1194.  
  1195.                 myErr = AECreateAppleEvent(kMyEventClass, kGetResEvent, &theAddress, kAutoGenerateReturnID, (*tempWCH)->windowID,
  1196.                                            &theEvent);
  1197.                 if (myErr == noErr) {
  1198.                     /* make a desc for the alias, and add it to the event */
  1199.  
  1200.                     HLock((Handle)theAlias);
  1201.                     myErr = AECreateDesc(typeAlias, (Ptr)*theAlias, GetHandleSize((Handle)theAlias), &tempDesc);
  1202.                     if (myErr == noErr) {
  1203.  
  1204.                         myErr = AEPutKeyDesc(&theEvent, keyDirectObject, &tempDesc);
  1205.  
  1206.                         /* now add a desc for the resType */
  1207.                         AEPutParamPtr(&theEvent, kMyResTypeParam, typeMyResType, (Ptr)&theType, sizeof(theType));
  1208.                         
  1209.                         /* here's where you'd add the quit code if you want to */
  1210.                         if (quit) {
  1211.                             AEPutKeyPtr(&theEvent, keyMyQuitFlag, typeBoolean, (Ptr)&quit, sizeof(quit));
  1212.                         }
  1213.  
  1214.                         if (myErr == noErr) {
  1215.  
  1216.                             /* do the actual sending */
  1217.                             myErr = AESend(&theEvent, nil, kAENeverInteract + kAEQueueReply, kAENormalPriority, kAEDefaultTimeout,
  1218.                                            nil, (EventFilterProcPtr)CommonIdleFunction);
  1219.  
  1220.                                 AEDisposeDesc(&theEvent);
  1221.                             
  1222.                         }
  1223.                     }
  1224.                     AEDisposeDesc(&tempDesc);
  1225.  
  1226.                 }
  1227.             } else {
  1228.                 /* couldn't launch the process for some reason or 'nother */
  1229.                 StopAlert(kCouldntFindProc, nil);
  1230.             }
  1231.         }
  1232.         DisposHandle((Handle)theAlias);
  1233.  
  1234.     }
  1235. }
  1236.  
  1237. /* AEAnswerHandler */
  1238. /* Since I'm sending my event with kAEQueueReply, that means that my reply will */
  1239. /* come into my event loop as a standard appleevent of type kAEAnswer */
  1240. /* this is my handler for those types of events */
  1241. pascal OSErr AEAnswerHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  1242. {
  1243. #pragma unused (reply,refIn)    
  1244.     /* yank my information, and put it in my list */
  1245.     OSErr myErr;
  1246.     WindowPtr theWindow;
  1247.     myResInfoPtr nowInfo = NewPtrClear(sizeof(myResInfoStruct));
  1248.     OSErr listErr = noErr;
  1249.     WindowPtr tempWP;
  1250.     unsigned long theLong;
  1251.     AEDesc theList;
  1252.     Cell cSize =  {
  1253.         0, 0
  1254.     };
  1255.     Size sizeBack;
  1256.     long longErr = nil;
  1257.     DescType typeBack;
  1258.     /* get our transaction ID, which matches the window ID */
  1259.     /* First thing we look for is an error */
  1260.     myErr = AEGetParamPtr(messagein, keyErrorNumber, typeLongInteger, &typeBack, (Ptr)&longErr, sizeof(long), &sizeBack);
  1261.     if (myErr == noErr) {
  1262.         /* if there was no error, that means that an error was returned */
  1263.         /* kind of backwards, but what that means is.... */
  1264.         /* A error from the other process comes back to me as a parameter in the */
  1265.         /* event.  If I CAN pull that parameter (i.e. noErr result from above ) that */
  1266.         /* means that an error exists. */
  1267.         /* If I CAN'T pull the error descriptor, that means that I do not have an error */
  1268.         SayError(longErr);
  1269.     }
  1270.     
  1271.     /* if there was noErr, or if the event just overflowed, then there is still much information */
  1272.     /* to display, so we'll display it */
  1273.     if (longErr == noErr || longErr == kAppleEventTooBig) {
  1274.     /* save the current port */
  1275.         GetPort(&tempWP);
  1276.         
  1277.         /* get the transaction ID, which equates to our unique window ID */
  1278.         AEGetAttributePtr(messagein, keyTransactionIDAttr, typeLongInteger, &typeBack, (Ptr)&theLong, sizeof(long), &sizeBack);
  1279.         
  1280.         /* find that window */
  1281.         theWindow = FindWindowByID(theLong);
  1282.  
  1283.         if (theWindow) {
  1284.             windowCHandle tempWCH = (windowCHandle)GetWRefCon(theWindow);
  1285.             SetPort(theWindow);
  1286.             /* get rid of all current contents */
  1287.             LDelRow(0, 0, (*(documentExtraDataHdl)((*tempWCH)->generalData))->displayList);
  1288.  
  1289.             /* turn off drawing whilst adding */            
  1290.             LDoDraw(false, (*(documentExtraDataHdl)((*tempWCH)->generalData))->displayList);
  1291.             
  1292.             /* get the direct object, which is my list */
  1293.             myErr = AEGetKeyDesc(messagein, keyDirectObject, typeAEList, &theList);
  1294.             if (myErr == noErr) {
  1295.                 /* we got us a list of stuff, start pulling and adding it to our window */
  1296.                 long listCount;
  1297.                 long currentIndex;
  1298.                 AECountItems(&theList, &listCount);
  1299.  
  1300.                 /* index through all the things I got back, and add them to the list */
  1301.                 /* list is 1, not 0, based */
  1302.                 for (currentIndex = 1; currentIndex <= listCount; currentIndex++) {
  1303.                 
  1304.                     Str15 theNumberString;
  1305.                     AEGetNthPtr(&theList, currentIndex, typeMyResInfoType, nil, &typeBack, (Ptr)nowInfo, sizeof(myResInfoStruct),
  1306.                                 &sizeBack);
  1307.                     
  1308.                     /* add this info to my list */
  1309.                     
  1310.                     LAddRow(1, cSize.v, (*(documentExtraDataHdl)((*tempWCH)->generalData))->displayList);   /* a new item, add a row for it */
  1311.                     
  1312.                     NumToString(nowInfo->id, theNumberString);
  1313.                     LAddToCell(&theNumberString[1], theNumberString[0], cSize,
  1314.                                (*(documentExtraDataHdl)((*tempWCH)->generalData))->displayList);
  1315.                     cSize.h++;
  1316.                     NumToString(nowInfo->length, theNumberString);
  1317.                     LAddToCell(&theNumberString[1], theNumberString[0], cSize,
  1318.                                (*(documentExtraDataHdl)((*tempWCH)->generalData))->displayList);
  1319.                     cSize.h++;
  1320.                     
  1321.                     LAddToCell(&nowInfo->theType, 4, cSize, (*(documentExtraDataHdl)((*tempWCH)->generalData))->displayList);
  1322.                     cSize.h++;
  1323.                     
  1324.                     LAddToCell(&nowInfo->theName[1], nowInfo->theName[0], cSize,
  1325.                                (*(documentExtraDataHdl)((*tempWCH)->generalData))->displayList);
  1326.                     
  1327.                     cSize.h = 0;
  1328.                     
  1329.                     cSize.v++;
  1330.                     
  1331.                 /* Here's an additional check I'm adding */
  1332.                 /* Since I'm using the standard text LDEF, I have a 32k limit on the  */
  1333.                 /* data, so I'm checking the data handle to see if I'm going  */
  1334.                 /* to explode the next pass through */
  1335.                 if(GetHandleSize((Handle)(*(*(documentExtraDataHdl)((*tempWCH)->generalData))->displayList)->cells) > 30000)
  1336.                 {
  1337.                 listErr = kListGrewTooBig;
  1338.                 break;
  1339.                 }
  1340.                 }
  1341.                 LDoDraw(true, (*(documentExtraDataHdl)((*tempWCH)->generalData))->displayList);
  1342.                 
  1343.                 InvalRect(&theWindow->portRect);
  1344.             }
  1345.             AEDisposeDesc(&theList);
  1346.         } else {
  1347.             DebugStr("\p didn't find widow with ID ");
  1348.         }
  1349.         SetPort(tempWP);
  1350.     }                                                       /* error if else */
  1351. if(listErr)SayError(listErr);
  1352.  
  1353. if(nowInfo)
  1354.     DisposPtr((Ptr)nowInfo);
  1355.  
  1356. return(myErr);
  1357. }
  1358.  
  1359. /* Finds the window with this unique ID */
  1360. WindowPtr FindWindowByID(unsigned long askedID)
  1361. {
  1362.     WindowPtr currentWP = FrontWindow();
  1363.     while (currentWP) {
  1364.         windowCHandle tempWCH = (windowCHandle)GetWRefCon(currentWP);
  1365.         if ((*tempWCH)->windowID == askedID) {
  1366.             break;
  1367.         } else {
  1368.             currentWP = (WindowPtr)((WindowPeek)currentWP)->nextWindow;
  1369.         }
  1370.     }
  1371.     return(currentWP);
  1372. }
  1373.  
  1374. /* AddWindowID */
  1375. /* This adds a unique ID to our documents, so we can always match */
  1376. /* ids to AppleEvent transactions */
  1377. void AddWindowID(WindowPtr theWindow)
  1378. {
  1379.     WindowPtr currentWindow;
  1380.     windowCHandle tempWCH;
  1381.     
  1382.     unsigned long theID = TickCount();                      /* use tickcount to start */
  1383.     Boolean dupedID = false;
  1384.     do {
  1385.         currentWindow = FrontWindow();
  1386.         do {
  1387.             if (IsMyWindow(currentWindow)) {
  1388.                 tempWCH = (windowCHandle)GetWRefCon(currentWindow);
  1389.                 if ((*tempWCH)->windowID == theID) {
  1390.                     dupedID = true;
  1391.                     break;
  1392.                 }
  1393.             }
  1394.             currentWindow = (WindowPtr)((WindowPeek)currentWindow)->nextWindow;
  1395.             
  1396.         }
  1397.                 while (currentWindow);
  1398.         
  1399.         if (!dupedID)
  1400.             break;
  1401.         else                                                /* add 1 and try again */
  1402.             theID++;
  1403.     }
  1404.             while (true);
  1405.     tempWCH = (windowCHandle)GetWRefCon(theWindow);
  1406.     (*tempWCH)->windowID = theID;
  1407.     
  1408. }
  1409.  
  1410. void ActivateMain(WindowPtr theWindow,Boolean activate)
  1411. {
  1412. WindowPtr tempWP;
  1413. Rect scratchRect;
  1414. RgnHandle tempRgn;
  1415. windowCHandle tempWCH = (windowCHandle)GetWRefCon(theWindow);
  1416. LActivate(activate, (*(documentExtraDataHdl)((*tempWCH)->generalData))->displayList);
  1417. GetPort(&tempWP);
  1418. SetPort(theWindow);
  1419. /* make sure the grow box gets drawn dimmed */
  1420.     /* clip to the area the grow box is in, and draw it */
  1421.     scratchRect = theWindow->portRect;
  1422.     scratchRect.top = scratchRect.bottom - 15;
  1423.     scratchRect.left = scratchRect.right - 15;
  1424.     tempRgn = NewRgn();
  1425.     GetClip(tempRgn);
  1426.     ClipRect(&scratchRect);
  1427.     DrawGrowIcon(theWindow);
  1428.     SetClip(tempRgn);
  1429.     DisposeRgn(tempRgn);
  1430.  
  1431. SetPort(tempWP);
  1432.  
  1433. }
  1434. void CloseTheWindow(WindowPtr theWindow)
  1435. {
  1436.     windowCHandle tempWCH;
  1437.     if (IsMyWindow(theWindow)) {
  1438.         tempWCH = (windowCHandle)GetWRefCon(theWindow);
  1439.         LDispose((*(documentExtraDataHdl)((*tempWCH)->generalData))->displayList);
  1440.         DisposHandle((Handle)tempWCH);
  1441.         DisposeWindow(theWindow);
  1442.         
  1443.     }
  1444. }
  1445.  
  1446. void AdjustMenus(void)
  1447. {
  1448.     if (IsMyWindow(FrontWindow())) {
  1449.         EnableItem(GetMHandle(kFileMenu), kCloseItem);
  1450.         EnableItem(GetMHandle(kToolsMenu), 1);
  1451.         
  1452.     } else {
  1453.         DisableItem(GetMHandle(kFileMenu), kCloseItem);
  1454.         DisableItem(GetMHandle(kToolsMenu), 1);
  1455.         
  1456.     }
  1457.     EnableItem(GetMHandle(kFileMenu),kNewItem);
  1458. }
  1459.  
  1460. void ReDrawGridLines(WindowPtr theWindow, ListHandle theList)
  1461. {
  1462.     register qq;
  1463.     short cellWide, cellHi;
  1464.     cellHi = (*theList)->cellSize.v;
  1465.     cellWide = (*theList)->cellSize.h;
  1466.     
  1467.     /* draw some lines to divide the cells */
  1468.     for (qq = 1; qq < 4; qq++) {
  1469.         MoveTo(cellWide * qq, kTopLineHeight);
  1470.         LineTo(cellWide * qq, theWindow->portRect.bottom - kScrollBarFudge);
  1471.     }
  1472.     /* now some horriZontal lines */
  1473.     for (qq = 0; qq < (((theWindow->portRect.bottom - theWindow->portRect.top) - kTopLineHeight) / cellHi); qq++) {
  1474.         MoveTo(0, (cellHi * qq) + kTopLineHeight-1);
  1475.         
  1476.         LineTo(theWindow->portRect.right - kScrollBarFudge, (cellHi * qq) + kTopLineHeight-1);
  1477.     }
  1478. }
  1479.  
  1480. void SayError(long longErr)
  1481. {
  1482.     Str32 theString;
  1483.     Str255 words;
  1484.     words[0] = 0;
  1485.  
  1486.     NumToString(longErr, theString);
  1487.     if (longErr == kAppleEventTooBig)
  1488.         GetIndString(words, kGeneralStrings, kBigAEWords);
  1489.     if (longErr == kListGrewTooBig)
  1490.         GetIndString(words, kGeneralStrings, kBigListWords);
  1491.  
  1492.     ParamText(theString, words, "", "");
  1493.     StopAlert(kMDeamonError, nil);
  1494.     
  1495. }
  1496.  
  1497. pascal Boolean standardDialogFilter(DialogPtr theDialog, EventRecord *theEvent, short *itemHit)
  1498. {
  1499.     ModalFilterProcPtr stdProc;
  1500.     windowCHandle tempWCH;
  1501.     Boolean returnVal = false;
  1502.     
  1503.     if (theEvent->what == updateEvt && theEvent->message != theDialog) {
  1504.         WindowPtr theWindow = (WindowPtr)theEvent->message;
  1505.         /* draw my window if it's really mine */
  1506.         if (IsMyWindow(theWindow)) {
  1507.             tempWCH = (windowCHandle)GetWRefCon(theWindow);
  1508.             (ProcPtr)((*tempWCH)->drawMe)(theWindow);
  1509.             
  1510.             
  1511.             *itemHit = 0;
  1512.             returnVal = false;                              /* tell the dialog manager I handled this event */
  1513.         }
  1514.     } else {
  1515.         /* first see if I have an extra filter in */
  1516.         if (gExtraDialogFilter)
  1517.             returnVal = gExtraDialogFilter(theDialog, theEvent, itemHit);
  1518.         if (returnVal == false) {
  1519.             GetStdFilterProc(&stdProc);
  1520.             returnVal = ((ModalFilterProcPtr)stdProc)(theDialog, theEvent, itemHit);
  1521.         }
  1522.     }
  1523.     return(returnVal);
  1524. }
  1525.  
  1526. /* end standardDialogFilter */
  1527.  
  1528. pascal Boolean standardAlertFilter(DialogPtr theDialog, EventRecord *theEvent, short *itemHit)
  1529. {
  1530.     windowCHandle tempWCH;
  1531.     Boolean returnVal = false;
  1532.     if (theEvent->what == updateEvt && theEvent->message != theDialog) {
  1533.         WindowPtr theWindow = (WindowPtr)theEvent->message;
  1534.         /* draw my window if it's really mine */
  1535.         /* draw my window if it's really mine */
  1536.         if (IsMyWindow(theWindow)) {
  1537.             tempWCH = (windowCHandle)GetWRefCon(theWindow);
  1538.             ((*tempWCH)->drawMe)(theWindow);
  1539.         }
  1540.     } else {
  1541.         /* for alerts we have to check for keys ourselves, since we didn't have a chance to */
  1542.         /* call SetDialogCancel or anything */
  1543.         
  1544.         if ((theEvent->what == keyDown) || (theEvent->what == autoKey)) {
  1545.             short tempItem;
  1546.             Handle tempHandle;
  1547.             Rect tempRect;
  1548.             char theKey = theEvent->message &charCodeMask;
  1549.             switch (theKey) {
  1550.                 long tilticks;
  1551.                 case kReturnKey:
  1552.                 case kEnterKey:                             /* enter key */
  1553.                     /* This filters for Return or Enter as item 1, and Esc as item 2 */
  1554.                     *itemHit = 1;                           /* change whatever the current item is to the OK item */
  1555.                     /* now we need to invert the button */
  1556.                     GetDItem(theDialog, 1, &tempItem, &tempHandle, &tempRect);
  1557.                     if (tempItem == ctrlItem) {
  1558.                         /* double check for the unlikely event that this is _not_ a button */
  1559.                         HiliteControl(SnatchHandle(theDialog, ok), inButton);
  1560.                         Delay(8, &tilticks);                /* wait about 8 ticks so they can see it */
  1561.                         HiliteControl(SnatchHandle(theDialog, ok), false);
  1562.                         
  1563.                         returnVal = true;
  1564.                     }
  1565.                     break;
  1566.                     /* This filters the escape key as the same as item 2 (the canx button, usually ) */
  1567.                 case kEscKey:
  1568.                     *itemHit = 2;
  1569.                     if (tempItem == ctrlItem) {
  1570.                         /* much more likely that this may not be a button */
  1571.                         
  1572.                         HiliteControl(SnatchHandle(theDialog, cancel), inButton);
  1573.                         Delay(8, &tilticks);                /* wait about 8 ticks so they can see it */
  1574.                         HiliteControl(SnatchHandle(theDialog, cancel), false);
  1575.                         returnVal = true;
  1576.                     }
  1577.                     break;
  1578.             }
  1579.         }
  1580.     }
  1581.     return(returnVal);
  1582. }
  1583.  
  1584. /* end standardDialogFilter */
  1585.  
  1586.  
  1587.